﻿#include "imghost_api.h"
#include "cross_com.h"
#include <map>
#include <vector>
#include "global_com.h"
#include "stor_cache_cfg.h"
#include "record_stor.h"

using namespace std;

STORAGE_STATUS_CBAK         g_status_bak    = NULL;
HM_GetFrame                 g_func_GetFrame = NULL;

void InitStorCacheCfg()
{
    CStorCacheCfg * pCfg = CStorCacheCfg::getSingleton();

    pCfg->SetChNum(g_storageCfg.channelNum);
    //主码流录像
    pCfg->SetMediaCacheSz(g_storageCfg.main_media_cache);
    pCfg->SetMoveDataBufSz(g_storageCfg.buf_sz_frame);
    pCfg->SetFlushBufSz(g_storageCfg.buf_sz_flush);

    //回放缓存大小
    if(g_storageCfg.buf_sz_replay != 0)
    {
        pCfg->SetReplayBufSz(g_storageCfg.buf_sz_replay);
    }
}

int HM_Storage_Init(StorageConfig cfg)
{
    int ret = 0;
    int bufSize = SIZE_1MB;
    int chNum = g_storageCfg.channelNum = cfg.channelNum;
	int ch = 0;
	CH_CFG_T * pChCfg = NULL;

	memcpy(&g_storageCfg,&cfg,sizeof(StorageConfig));

	InitStorCacheCfg();

	commondata_init();

	g_pFrmBufArr = new CFIFO_PTMFrame[chNum];
	for (int i = 0; i < chNum; i++)
	{
		bufSize = cfg.main_media_cache;
     
		ret = g_pFrmBufArr[i].Open(bufSize, 0, i);
		if (ret < 0)
		{
			printf("HM_Init Open ch %d fail.\n", i);
		}
		else
		{
			printf("CH%02d Storge Init FIFO BUF,size %d \n", i, bufSize);
		}
	}

    //开启录像
    printf("HM_Storage_Init ok.\n");
    return 0;
}

int  HM_Storage_UnInit()
{


	return 0;

}
#ifndef _WIN32
int AllocSpace(const char * filePath, uint32_t fileSpace)
{
	int fd = open(filePath, O_RDWR | O_CREAT, 0666);
	if (fd < 0)
	{
		fd = open(filePath, O_RDWR | O_CREAT, 0666);
		if (fd < 0) //重试再一次打开
		{
			int err = errno;
			printf("filePath %s Alloc file fail !!! errno %d str %s .\n", filePath, err, strerror(err));
			return ERR_FILE_OPEN;
		}
	}

	lseek(fd, fileSpace - 1, SEEK_SET);

	if (1 != write(fd, "1", 1))
	{
		//		printf("errno %d str %s .\n",errno,strerror(errno));
		//	printf("errno %d \n", errno);
	}

	close(fd);
	return 0;
}
#endif
time_t HM_GetRecMaxTime()
{
    int64_t recTm = 0;
    time_t destTm = 0;
  
    destTm = (time_t)(recTm/1000);

    return destTm;
}

#ifndef _WIN32
int my_system(const  char * cmd)
{
    FILE * fp;
    int res = 0;
    char buf[1024];
    int result = 0;

    if (cmd == NULL)
    {
        fprintf(stderr, "my_system cmd is NULL\n");
        return -1;
    }
    fprintf(stderr, "cmd ->%s\n",cmd);
    if ((fp = popen(cmd, "r") ) == NULL)
    {
        perror("popen");
        fprintf(stderr, "popen error: %s\n", strerror(errno));
        return -1;
    }
    else
    {
        while(fgets(buf, sizeof(buf), fp))
        {
            fprintf(stderr, "%s\n", buf);
            result ++;
            if(result == 9999999)				//超时退出 ? 。。。。大概10秒的样子。
            {
                fprintf(stderr, "my_system Timeout !!!\n");
                break;
            }
        }
        if((res = pclose(fp)) == -1)
            fprintf(stderr, "close popen file pointer fp error!\n");
        return res;
    }
}
#endif
//判断磁盘是否已经初始化
int HM_disk_is_init(const char * dev)
{
	bool bRawDev = 0;

    //通用文件系统
    if(bRawDev)
    {
        fprintf(stderr,"Storage disk %s not init .\n",dev);
    }
    else
    {

    }
    return false;
}

//设置读取音视频接口
void  HM_SET_GetFrame_CBK(HM_GetFrame cbak_funcGetFrame)
{
    g_func_GetFrame = cbak_funcGetFrame;
    if(cbak_funcGetFrame != NULL)
    {
        g_storageCfg.bDisableCache = true;
    }
}

void HM_SET_STATUS_CBAK(STORAGE_STATUS_CBAK cbak)
{
    g_status_bak = cbak;
}

int HM_Snap(int ch)
{
    return 0;
}

int HM_RecordStart(int ch)
{
    //开启底层编码功能
    
    //开启录像
    record_start(ch);

    return 0;
}

int HM_RecorcStop(int ch)
{
    //关闭录像
    record_stop(ch);
    //关闭底层编码功能
    return 0;
}

int HM_CycleRec(int bEnable)
{
    bool bCycle = false;
    if(bEnable == 0)
    {
        bCycle = false;
    }
    else
    {
        bCycle = true;
    }

    return 0;
}
int HM_PicSearch(char* fileBuf, int bufSize, time_t tmStart, time_t tmEnd, int32_t chMask)
{
	return 0;
}




int HM_ManualRecStop(int ch)
{
    TRACE_CBS("Stop pauseRecord  CH %02d.\n",ch);

    return 0;
}


static int STORAGE_FORMAT_RAW(const char * dev,int recSizeMB,int comdiskMB,int useSpaceMB)
{
    int ret = 0;
	char * pDevice = (char*)dev;


    fprintf(stderr,"Format disk  %s  OK.\n",dev);
    return ret;
}

static int STORAGE_FORMAT_COM(const char * dev,int recSizeMB)
{
    int ret = 0;
  
    uint32_t fileSizeMB    = 128;
	uint32_t fileSize = 0;// SIZE_MB(fileSizeMB);
    uint32_t indexInfoSize = SIZE_4KB;
    if(recSizeMB >= 64)
    {
        fileSizeMB = recSizeMB;
    }
	fileSize = SIZE_MB(fileSizeMB);
	if(ret < 0)
    {
        fprintf(stderr,"Init file index fail filesize %d dev %s.\n",fileSize,dev);
        return ret;
    }
    //预览分配8个文件录像文件,以便于后续文件录像中途不会停顿太久
    uint32_t index = 0;
    char filePath[60] = {0};
    char tmpPath[60] = {0};
    char cmd[60] = {0};


    if(-1 == access(filePath,0))
    {
#ifdef _WIN32
        strcat(tmpPath,"Record\\");
#else
        strcat(tmpPath,"Record/");
        sprintf(cmd,"mkdir -p %s",tmpPath);
        system(cmd);
#endif
    }

    //初始五分钟避免时间太久
	uint32_t maxFileNum = 0;
    time_t startTm,curIm,endTm;
    time_t totalSecs = 0;
    int    failCnt   = 0;

    time(&startTm);

    for(index = 0; index < maxFileNum; index++)
    {
        sprintf(filePath,"%s%05d.asf",tmpPath,index);
        if(-1 == access(filePath,0))
        {
           // ret = CSerialFileBase::AllocSpace(filePath,fileSize);
            if(ret < 0)
            {
                if(failCnt >= 3)
                {
                    break;
                }
                TRACE_ERR("Alloc file fail. index %d \n",index);
                failCnt ++;
            }
        }
        time(&curIm);
    }

    time(&endTm);
    totalSecs = endTm - startTm;
    TRACE_ERR("Total AllocSpace time %d s total rec num %d file size %d MB.\n",totalSecs,maxFileNum,fileSizeMB);

    return ret;
}

int HM_FormatToRecdisk(const char * dev,int recSizeMB,int comdiskMB,int useSpaceMB)
{
    int ret = 0;
    if(dev == NULL)
    {
        fprintf(stderr,"No device  %s.\n",dev);
        return ERR_NO_DEVICE;
    }
    if(comdiskMB >10 * 1024)
    {
        TRACE_ERR("comdisk is too big.\n");
        comdiskMB = 10 * 1024;  //将其限制在10G以内
    }
#ifdef _WIN32
    if(strstr(dev,"\\\\.\\PhysicalDrive"))
#else
    if(strstr(dev,"/dev/sd") ||
            strstr(dev,"/dev/mmc")  )
#endif
    {
        //裸设备格式化
        ret = STORAGE_FORMAT_RAW(dev,recSizeMB,comdiskMB, useSpaceMB);
    }
    else
    {
        ret = STORAGE_FORMAT_COM(dev,recSizeMB);
    }

    return ret;
}

int HM_FifoWriteFrame(unsigned char * buf,uint32_t dataSize,int frameType,int ch)
{
    if( NULL == g_pFrmBufArr)
    {
        return ERR_DATA_BUF_EMPYT;
    }
    if( ch >= g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }
    if(dataSize == 0)
    {
        return ERR_DATA_SIZE;
    }
    CFIFO_PTMFrame * pFIFO =  &g_pFrmBufArr[ch];

    int ret = pFIFO->WriteFrame(buf,dataSize,frameType);

    return ret;
}

int HM_FifoConsumeFrame(int  frmSize,int ch,int clientID)
{
    if(ch >= g_storageCfg.channelNum)
    {
        return ERR_OVER_MAXCLIENT;
    }

    CFIFO_PTMFrame * pFIFO =  &g_pFrmBufArr[ch];
    int ret = pFIFO->ConsumeFrame(frmSize,clientID);
    return ret;
}


int HM_FifoGetFrameWater(int ch,int clientID)
{
    if( NULL == g_pFrmBufArr)
    {
        return ERR_DATA_BUF_EMPYT;
    }

    if( ch >= g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }

    int ret = 0;
    CFIFO_PTMFrame *pFIFO = & g_pFrmBufArr[ch];

    ret = pFIFO->GetDataWater(clientID);
    return ret;

}

int  HM_FifoReadFrame(unsigned char * buf,uint32_t dataSize,int ch,int clientID)
{
    int ret = 0;

    if( NULL == g_pFrmBufArr)
    {
        return ERR_DATA_BUF_EMPYT;
    }

    if( ch >= g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }


    CFIFO_PTMFrame *pFIFO = & g_pFrmBufArr[ch];
    ret = pFIFO->ReadFrame(buf,dataSize,clientID);

    return ret;
}

int  HM_FifoSeekTime(int64_t startTime, int prepareSecs, int ch, int clientID)
{
	int ret = 0;

	if (NULL == g_pFrmBufArr)
	{
		return ERR_DATA_BUF_EMPYT;
	}

	if (ch >= g_storageCfg.channelNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CFIFO_PTMFrame *pFIFO = &g_pFrmBufArr[ch];
	ret = pFIFO->SeekTime(startTime, prepareSecs);

	return ret;
}



int HM_FifoClearData(int ch)
{
    if( NULL == g_pFrmBufArr)
    {
        return ERR_DATA_BUF_EMPYT;
    }

    if( ch >= g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }
    int ret = 0;
    CFIFO_PTMFrame *pFIFO = &g_pFrmBufArr[ch];
    pFIFO->reset();
    return ret;
}

RECORD_CH_INFO HM_GetRecordChInfo()
{
    RECORD_CH_INFO chInfo;

    chInfo.chManualBIT = g_storageCfg.manualRecBIT ;
    chInfo.sptChNum    = g_storageCfg.channelNum;

    memset(chInfo.recType,0,32);

    for(int ch = 0; ch < g_storageCfg.channelNum; ch++)
    {
        chInfo.recType[ch] = 1;//(char)g_pRecSet->RecordType(ch);
    }

    return chInfo;
}


void HM_SetRecordCycle(uint8_t bEnable)
{
    g_storageCfg.bCycleRec = bEnable;

}

int HM_SetPreareRec(uint8_t bEnable, int nSecs)
{
    g_storageCfg.bPrepare = bEnable;
    return 0;
}



int HM_SearchRecordDayOfMonth(int year, int month, int recType)
{
    int64_t tmStart = 0;
    int64_t tmEnd = 0;
    int chNum = g_storageCfg.channelNum;
    vector<int32_t> vecDayBIT(32);
    int dayBIT = 0;
	int ret = 0;//

    if(ret > 0 )
    {
        for(int i = 0 ; i < chNum; i++ )
        {
            if(vecDayBIT[i])
            {
                dayBIT |= vecDayBIT[i];
            }
        }
    }

    return dayBIT;
}

int HM_SearchRec( char* fileBuf,int bufSize,time_t tmStart, time_t tmEnd, int32_t chMask,int recType,int storType,int clientID)
{
    int ret      = 0;
    char* recBuf = fileBuf;
    int recPos   = 0;
    int  maxFileNum = bufSize /sizeof(RECORD_SEGMENT);
    int  ch = 0;
    bool bSameRec = false;
    TRACE("1 SerchRecord start clientID %d chLst %d recType %d start time %ld end time %ld maxFileNum %d.\n",
          clientID, chMask,recType,tmStart,tmEnd,maxFileNum);

    PrintTimeSec(tmStart,tmEnd,(char *)"Search Time");

    int64_t tmStartMS = (int64_t)tmStart * 1000;
    int64_t tmEndMS   = (int64_t)tmEnd   * 1000;
    if( NULL == recBuf)
    {
        return ERR_DATA_BUF_EMPYT;
    }

    if(tmStart > tmEnd)
    {
        TRACE_ERR("Error search time %ld %ld .\n",tmStart,tmEnd);
        PrintTimeSec(tmStart,tmEnd,NULL);
        return ERR_PARAM;
    }

    if( 0 == chMask)
    {
        TRACE("Channel list is empty.\n");
        return ERR_PARAM;
    }

    return recPos;
}

int HM_SearchRecfile(time_t tmStart, time_t tmEnd, int32_t chMask)
{
    uint32_t ret_num = 0;
    TRACE("HM_SearchRecfile \n");
    unsigned char* p_flst = NULL;
    PrintTimeSec(tmStart, tmEnd, (char*)"Search Time");
    
    g_lst_files.clear();

    ret_num = g_file_list->search_file(g_storageCfg.record_path, g_lst_files,g_storageCfg.record_file_ext,3,true);

    if (ret_num != 0)
    {
        p_flst = g_flst_shm.m_pShareMem;
        memcpy(p_flst, &ret_num,4);
        REC_FINFO* pRec = (REC_FINFO*)(p_flst + 4);
        int item_cnt = 0;
        for (auto it:g_lst_files)
        {
            pRec = (REC_FINFO*)(p_flst + 4 + sizeof(REC_FINFO)* item_cnt);
            strcpy(pRec->frec_path ,it.name.c_str());
            pRec->file_sz = it.size;
            item_cnt++;
        }
        //响应命令
    }

    return ret_num;
}

//回放接口,可以支持远程点播,        ClientID  0:表示本地用户　　1：远程用户　
int HM_PlaybackBytime(time_t startTime,time_t endTime, int channel,int clientID)
{
    int ret = 0;
    int64_t tmStart = (int64_t)startTime * 1000;
    int64_t tmEnd   = (int64_t)endTime * 1000;

    TRACE_ERR("Telnet replay channel %d clientID %d.\n ",channel,clientID);
    PrintTimeMs(tmStart,tmEnd,"telnet replay time");
    if(channel > g_storageCfg.channelNum)
    {
        return ERR_PARAM;
    }

    return ret;
}



int  HM_PlaybackByFile(const char* file, time_t startTime)
{
    int ret = 0;
    
    printf("playback file %s ", file);
    PrintTimeSec(startTime,0,"start time");
    int64_t start_tm = (int64_t)startTime*1000;
    uint32_t file_idx = 0;

    ret = g_recreader->Open(file, start_tm,0,true);

    return ret;
}

int HM_PlaybackStop(int ch,int clientID)
{
    int ret = 0;
    TRACE("HM_PlaybackStop ch %d \n",ch);

    return ret;
}

int  HM_PlaybackStatus(int ch,time_t playTime,int clientID)
{
   // TRACE("HM_PlaybackStatus ch %d playTime %d\n", ch, playTime);

	return 0;
}

int HM_PlaybackSeekTime(time_t time,int ch,int clientID)
{
    int ret = 0;
    TRACE("PLAYBACK_SEEKTIME time %d  ch %d clientID %d.\n ",(int)time,ch,clientID);
    int64_t seekTime = (int64_t)time * 1000;

    PrintTimeMs(seekTime,0,"PLAYBACK_SEEKTIME");

    return ret;
}

int HM_PlaybackSetMode(int playMod, int speed,int ch,int clientID)
{
    int ret = 0;
    TRACE("HM_PlaybackSetMode  ch %d clientID %d.\n ", ch, clientID);
    return 0;
}

int  HM_PlaybackGetTime(int ch, int clientID)
{
    int ret = 0;
    TRACE("HM_PlaybackGetTime  ch %d clientID %d.\n ", ch, clientID);
    return 0;
}

//磁盘管理接口
int HM_GetDiskInfo(char * buf,int bufSize)
{
    int ret = 0;
    TRACE("getDiskInfo Start bufSize %d  \n",bufSize);
    int infoLen    = sizeof(DiskInfo);
    char * diskBuf = (char *)buf;
    DiskInfo apiDiskInfo;
    int diskCnt = 0;
    int usbDiskCnt = 0;
    int fileMB  = 0;
    
    memset(diskBuf,0,bufSize);
 //   TRACE("HM_GetDiskInfo  ch %d clientID %d.\n ", ch, clientID);
    return diskCnt;
}


StorageConfig HM_GetStorageCfg()
{
    return g_storageCfg;
}

StorageSpaceInfo HM_GetDiskSpaceInfo()
{
    StorageSpaceInfo spaceInfo;


    return spaceInfo;
}

int HM_FifoGetDataSize(int ch)
{
    if(ch > g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }

    int ret =0;

    ret = g_pFrmBufArr[ch].GetFrameSize(0);

    return ret;
}

int HM_FIFOGetWarter(int ch)
{
    if(ch > g_storageCfg.channelNum)
    {
        return ERR_OVER_MAX_CHANNEL;
    }
    int ret = 0;

    ret = g_pFrmBufArr[ch].GetCurWarter();

    return ret;
}



